package odgs.manager.filedb;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import odgs.Contents;
import odgs.ContentsFile;
import odgs.Directory;
import odgs.ExplorerNode;
import odgs.GridNode;
import odgs.Result;
import odgs.SaveUtil;
import odgs.manager.DBManager;

public class FileDBManager implements DBManager
{
	private FileDB data;
	private String fileName;
	private boolean isAutoSave = false;

	public FileDBManager(String filePath, boolean load, boolean autoSave)
	{
		fileName = filePath;
		this.isAutoSave = autoSave;
		if(load == true)
		{
			load();
		}
		else
		{
			data = new FileDB();
		}
	}
	
	public void load()
	{
		File file = new File(fileName);
		if(file.exists())
		{
			data = (FileDB) SaveUtil.load(file);
		}
		else
		{
			data = new FileDB();
		}
	}

	public void save()
	{
		File file = new File(fileName);
		SaveUtil.save(file, data);
	}

	public int getGridNodeCount()
	{
		synchronized (data)
		{
			return data.getGridNodeList().size();
		}
	}

	public int addGridNode(String id, long allowedSize, long usedSize)
	{ 
		FileDBGridNode node = new FileDBGridNode(id, allowedSize,usedSize);
		if(getGridNode(id) == null)
		{
			synchronized (data)
			{
				data.getGridNodeList().add(node);
				if(isAutoSave)
					save();
				return Result.OK;
			}
		}
		else
		{
			return Result.ID_IS_EXIST;
		}
	}


	public GridNode getGridNode(String id)
	{
		synchronized (data)
		{
			List<FileDBGridNode> nodes = data.getGridNodeList();
			for (FileDBGridNode node : nodes)
			{
				if(node.getId().equals(id))
				{
					return node.getGridNode();
				}
			}
		}
		return null;
	}

	public int removeGridNode(String id)
	{
		FileDBGridNode node = getFileDBGridNode(id);
		if(node != null)
		{
			synchronized (data)
			{
				List<FileDBGridNode> nodes = data.getGridNodeList();
				nodes.remove(node);
				if(isAutoSave)
					save();
			}
			return Result.OK;
		}
		else
		{
			return Result.ID_IS_NOT;
		}
	}

	private FileDBGridNode getFileDBGridNode(String id)
	{
		synchronized (data)
		{
			List<FileDBGridNode> nodes = data.getGridNodeList();
			for (FileDBGridNode node : nodes)
			{
				if(node.getId().equals(id))
					return node;
			}
		}
		return null;
	}

	public int addContentsFile(String nodeId, int contentsUID, long start, long end) 
	{
		synchronized (data)
		{
			int uid = data.getContentsFilePrimaryKey();

			List<FileDBContentsFile> list = data.getContentsFileList();
			list.add(new FileDBContentsFile(uid, nodeId,contentsUID, start,end));

			if(isAutoSave)
				save();
			return uid;
		}
	}

	public void freeReservedStorage(String nodeId, long size) 
	{
		synchronized (data)
		{
			FileDBGridNode node = getFileDBGridNode(nodeId);
			if(node != null)
				node.freeReservedSize(size);
		}
	}

	public void useStorage(String nodeId, long size) 
	{
		synchronized (data) 
		{
			FileDBGridNode node = getFileDBGridNode(nodeId);
			if(node != null)
				node.useStorage(size);
		}
	}

	public long getTotalAllowedSize() 
	{
		long  size = 0;
		synchronized (data)
		{
			List<FileDBGridNode> nodes = data.getGridNodeList();
			for(FileDBGridNode node : nodes)
			{
				size += node.getAllowedSize();
			}
		}
		return size;
	}

	public void freeStorage(String nodeId, long size)
	{
		synchronized (data) 
		{
			FileDBGridNode node = getFileDBGridNode(nodeId);
			if(node != null)
				node.freeStorage(size);
		}
	}

	public void reserveStorage(String nodeId, long size)
	{
		synchronized (data)
		{
			FileDBGridNode node = getFileDBGridNode(nodeId);
			if(node != null)
				node.reserveStorage(size);
		}
	}

	public long getUsedSize()
	{
		long usedSize = 0;
		synchronized (data)
		{
			List<FileDBGridNode> list = data.getGridNodeList();
			for (FileDBGridNode node : list)
			{
				usedSize += node.getUsedSize();
			}
		}
		return usedSize;
	}

	public int addContents(String name, String type, String path, String owner, long size, int permission)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			int pk = data.getContentsPrimaryKey();
			list.add(new FileDBContents(pk,name,type,path,owner,size, permission));
			if(isAutoSave)
				save();
			return pk;
		}
	}

	public Contents getContents(String name, String type, String path)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				if(contents.getName().equals(name) && contents.getPath().equals(path) && contents.getType().equals(type))
				{
					return contents.getContents();
				}
			}
			return null;
		}
	}

	public int getContentsCount()
	{
		synchronized (data)
		{
			return data.getContentsList().size();
		}
	}

	public int removeContents(int uid)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				if(contents.getUid() == uid)
				{
					list.remove(contents);
					if(isAutoSave)
						save();
					return Result.OK;
				}
			}
			return Result.FAIL;
		}
	}

	public List<ContentsFile> getContentsFile(int contentsUID)
	{
		List<ContentsFile> files = new ArrayList<ContentsFile>();
		synchronized (data)
		{
			List<FileDBContentsFile> list = data.getContentsFileList();
			for (FileDBContentsFile file : list)
			{
				if(file.getContentsUid() == contentsUID)
				{
					Contents con = getContents(contentsUID);
					ContentsFile temp = new ContentsFile(file.getNodeId());
					temp.setEnd(file.getEnd());
					temp.setStart(file.getStart());
					temp.setUid(file.getUid());
					temp.setName(con.getName());
					temp.setPath(con.getPath());
					temp.setType(con.getType());
					temp.setContentsUID(contentsUID);
					files.add(temp);
				}	
			}
		}
		return files;
	}

	public Contents getContents(int contentsUID)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				if(contents.getUid() == contentsUID)
				{
					return contents.getContents();
				}
			}
			return null;
		}
	}

	public int removeContentsFile(int uid)
	{
		synchronized (data)
		{
			List<FileDBContentsFile> list = data.getContentsFileList();
			for (FileDBContentsFile file : list)
			{
				if(file.getUid() == uid)
				{
					list.remove(file);
					if(isAutoSave)
						save();
					return Result.OK;
				}
			}
			return Result.FAIL;
		}
	}

	public int getContentsFileCount()
	{
		synchronized (data)
		{
			return data.getContentsFileList().size();
		}
	}

	public int addDirectory(String name, String path, String owner, int permission)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			int pk = data.getDirectoryPrimaryKey();
			list.add(new FileDBDirectory(pk, name, path, owner, permission));
			if(isAutoSave)
				save();
			return pk;
		}
	}

	public int getDirectoryCount()
	{
		synchronized (data)
		{
			return data.getDirectoryList().size();
		}
	}

	public Directory getDirectory(int pk)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				if(directory.getUid() == pk)
				{
					return directory.getDirectory();
				}
			}
			return null;
		}
	}

	public void removeDirectory(int pk)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				if(directory.getUid() == pk)
				{
					list.remove(directory);
					if(isAutoSave)
						save();
					return;
				}		
			}
		}
	}

	public List<Contents> getTotalContents()
	{
		List<Contents> relist = new ArrayList<Contents>();
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				relist.add(contents.getContents());
			}
		}
		return relist;
	}

	public List<Directory> getTotalDirectory()
	{
		List<Directory> relist = new ArrayList<Directory>();
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				relist.add(directory.getDirectory());
			}
		}
		return relist;
	}

	public Directory getDirectory(String name, String path)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				if(directory.getName().equals(name) && directory.getPath().equals(path))
					return directory.getDirectory();
			}
		}
		return null;
	}

	public void renameContents(int uid, String destName)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				if(contents.getUid() == uid)
				{
					contents.setName(destName);
					if(isAutoSave)
						save();
					return;
				}
			}
		}
	}

	public void renameDirectory(int uid, String destName)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				if(directory.getUid() == uid)
				{
					directory.setName(destName);
					if(isAutoSave)
						save();
					return;
				}
			}
		}
	}

	public void updateChildNodePath(String sourcePath, String destPath)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				String temp = contents.getPath();
				if(temp.contains(sourcePath))
				{
					temp = temp.replaceAll(sourcePath, destPath);
					contents.setPath(temp);
				}
			}

			List<FileDBDirectory> list2 = data.getDirectoryList();
			for (FileDBDirectory dir : list2)
			{
				String temp = dir.getPath();
				if(temp.contains(sourcePath))
				{
					temp = temp.replaceAll(sourcePath, destPath);
					dir.setPath(temp);
				}
			}
			if(isAutoSave)
				save();
		}
	}

	public void moveContents(int uid, String destPath)
	{
		synchronized (data)
		{
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents contents : list)
			{
				if(contents.getContents().getUid() == uid)
				{
					contents.setPath(destPath);
					if(isAutoSave)
						save();
					return;
				}
			}
		}
	}

	public void moveDirectory(int uid, String destPath)
	{
		synchronized (data)
		{
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory directory : list)
			{
				if(directory.getUid() == uid)
				{
					directory.setPath(destPath);
					if(isAutoSave)
						save();
					return;
				}
			}
		}
	}

	public List<GridNode> getTotalGridNodes()
	{
		List<GridNode> result = new ArrayList<GridNode>();
		synchronized (data)
		{
			List<FileDBGridNode> list = data.getGridNodeList();
			for (FileDBGridNode node : list)
			{
				result.add(node.getGridNode());
			}
		}
		return result;
	}

	public List<ExplorerNode> findContentsByName(String keyword) {
		List<ExplorerNode> result = new ArrayList<ExplorerNode>();
		synchronized (data) {
			List<FileDBContents> list = data.getContentsList();
			for (FileDBContents file : list) {
				if(file.getName().matches("(?i).*" + keyword + ".*"))
				{
					result.add(file.getContents());
				}
			}
		}
		return result;
	}

	public List<ExplorerNode> findDirectoryByName(String keyword) {
		List<ExplorerNode> result = new ArrayList<ExplorerNode>();
		synchronized (data) {
			List<FileDBDirectory> list = data.getDirectoryList();
			for (FileDBDirectory file : list) {
				if(file.getName().matches("(?i).*" + keyword + ".*"))
				{
					result.add(file.getDirectory());
				}
			}
		}
		return result;
	}
}